#include "wifi_manager.h"
#include "motion_controller.h"
#include "led_control_center.h"

#include <ArduinoJson.h>

WiFiManager::WiFiManager(PatternLoader* loader, MotionController* motion, MotionController* motionForHoming, LEDManager* led) 
  : patternLoader(loader)
  , motionController(motion)
  , ledManager(led)
  , ledControlCenter(nullptr)
  , server(nullptr)
  , dnsServer(nullptr)
  , wifiConnected(false)
  , serverRunning(false)
  , apMode(false)
  , apSSID("沙画绘图机")
  , apPassword("")
  , lastWiFiCheck(0)
  , wifiMonitoring(false)
  , reconnectAttempts(0)
  , lastRetryTime(0)
  , currentRetryDelay(1000)
{
  // 初始化性能统计
  memset(&stats, 0, sizeof(stats));
  stats.bestSignalStrength = -100;
  
  logWithTimestamp("🏗️ WiFiManager 构造完成");
}

WiFiManager::~WiFiManager() {
  stopConfigPortal();
  stopWebServer();
  disconnectWiFi();
}

void WiFiManager::begin() {
  preferences.begin("wifi", false);
  
  // 添加强制配网模式检查（用于调试）
  Serial.println("🔧 WiFi管理器启动");
  Serial.println("💡 如需强制进入配网模式，请在串口输入: FORCE_CONFIG");
  
  // 尝试自动连接已保存的WiFi
  if (!autoConnect()) {
    Serial.println("🌐 未找到已保存的WiFi信息，启动配网模式");
    startConfigPortal();
  } else {
    Serial.println("✅ WiFi自动连接成功");
    Serial.println("💡 如需重新配网，请在串口输入: RESET_WIFI");
  }
}

bool WiFiManager::autoConnect() {
  if (loadWiFiCredentials()) {
    Serial.println("🔄 尝试连接已保存的WiFi...");
    return connectWiFi(ssid, password);
  }
  return false;
}

bool WiFiManager::startConfigPortal(const String& apName, const String& apPass) {
  apSSID = apName;
  apPassword = apPass;
  
  logWithTimestamp(String("📡 启动配网热点: ") + apSSID);
  
  // 步骤1: 配置AP模式
  if (!configureAPMode()) {
    return false;
  }
  
  // 步骤2: 启动DNS服务器
  if (!startDNSServer()) {
    logWithTimestamp("⚠️ DNS启动失败，但继续运行");
  }
  
  // 步骤3: 配置Web服务器路由
  if (!setupWebRoutes()) {
    logWithTimestamp("❌ Web服务器启动失败");
    return false;
  }
  
  // 输出配网信息
  logWithTimestamp(String("✅ 配网热点启动成功! IP: ") + WiFi.softAPIP().toString());
  logWithTimestamp(String("📡 热点名称: ") + WiFi.softAPSSID());
  logWithTimestamp(String("🔧 服务器状态: ") + (serverRunning ? "运行中" : "未运行"));
  logWithTimestamp(String("🌐 DNS状态: ") + (dnsServer ? "运行中" : "未运行"));
  
  // 输出使用说明
  Serial.println("=================================");
  Serial.println("📱 配网支持: Android 5.0+, iOS 9.0+, Windows 10+");
  Serial.println("📱 配网步骤:");
  Serial.println("1. 关闭手机移动数据");
  Serial.println("2. 连接'沙画绘图机'热点");
  Serial.println("3. 等待自动弹出配网页面");
  Serial.println("4. 手动访问: http://192.168.4.1");
  Serial.println("=================================");
  
  return true;
}

void WiFiManager::stopConfigPortal() {
  if (dnsServer) {
    dnsServer->stop();
    delete dnsServer;
    dnsServer = nullptr;
  }
  
  if (apMode) {
    WiFi.softAPdisconnect(true);
    apMode = false;
    Serial.println("📡 配网热点已关闭");
  }
}

bool WiFiManager::connectWiFi(const String& ssid, const String& password) {
  // 使用引用避免不必要的字符串复制
  this->ssid = ssid;
  this->password = password;
  
  logWithTimestamp(String("🌐 连接WiFi: ") + ssid);
  
  // 更新统计并设置LED状态
  updateConnectionStats(false);  // 先记录尝试连接
  
  if (ledManager && ledControlCenter) {
    ledControlCenter->requestStatusChange(LED_WIFI_CONNECTING, "WiFi连接中");
  }
  
  // 清理WiFi状态，使用常量定义的延迟
  WiFi.disconnect(true);
  delay(WIFI_DISCONNECT_DELAY);
  WiFi.mode(WIFI_STA);
  delay(WIFI_DISCONNECT_DELAY);
  
  // 开始连接
  WiFi.begin(ssid.c_str(), password.c_str());
  
  int attempts = 0;
  unsigned long startTime = millis();
  const unsigned long progressInterval = 500;
  unsigned long lastProgress = 0;
  
  // 连接循环，使用常量定义的最大尝试次数
  while (WiFi.status() != WL_CONNECTED && attempts < MAX_CONNECTION_ATTEMPTS) {
    unsigned long currentTime = millis();
    
    if (currentTime - lastProgress >= progressInterval) {
      Serial.print(".");
      lastProgress = currentTime;
      attempts++;
    }
    
    wl_status_t status = WiFi.status();
    
    // 处理连接错误
    if (status == WL_CONNECT_FAILED || status == WL_CONNECTION_LOST) {
      logWithTimestamp("⚠️ 检测到连接错误，重新尝试...");
      WiFi.disconnect(true);
      delay(1000);
      WiFi.begin(ssid.c_str(), password.c_str());
      startTime = currentTime;
    }
    
    // 超时检查，使用常量定义的超时时间
    if (currentTime - startTime > CONNECTION_TIMEOUT) {
      logWithTimestamp("⏰ 连接超时，重新尝试...");
      WiFi.disconnect(true);
      delay(1000);
      WiFi.begin(ssid.c_str(), password.c_str());
      startTime = currentTime;
    }
    
    delay(100);  // 减少CPU占用
  }
  
  bool connected = (WiFi.status() == WL_CONNECTED);
  wifiConnected = connected;
  
  if (connected) {
    Serial.println();
    updateConnectionStats(true);
    updateSignalStats();
    
    logWithTimestamp(String("✅ WiFi连接成功! IP: ") + WiFi.localIP().toString());
    
    if (ledManager && ledControlCenter) {
      ledControlCenter->requestStatusChange(LED_WIFI_CONNECTED, "WiFi连接成功");
    }
    
    // 自动启动Web服务器
    if (!serverRunning) {
      startWebServer();
      logWithTimestamp("🌐 Web服务器已自动启动");
      logWithTimestamp(String("🔗 浏览器访问: http://") + WiFi.localIP().toString());
    }
    
    return true;
  } else {
    Serial.println();
    logWithTimestamp("❌ WiFi连接失败");
    
    if (ledManager && ledControlCenter) {
      ledControlCenter->requestStatusChange(LED_WIFI_FAILED, "WiFi连接失败");
    }
    
    return false;
  }
}

void WiFiManager::disconnectWiFi() {
  if (wifiConnected) {
    WiFi.disconnect();
    wifiConnected = false;
    Serial.println("📶 WiFi已断开");
  }
}

bool WiFiManager::isConnected() {
  return WiFi.status() == WL_CONNECTED;
}

String WiFiManager::getIP() {
  if (isConnected()) {
    return WiFi.localIP().toString();
  } else if (apMode) {
    return WiFi.softAPIP().toString();
  }
  return "未连接";
}

bool WiFiManager::isAPMode() {
  return apMode;
}

// Captive Portal页面处理 - 手机优化版本
void WiFiManager::handleCaptivePortal() {
  IPAddress clientIP = server->client().remoteIP();
  String uri = server->uri();
  String userAgent = server->header("User-Agent");
  
  Serial.println("� === Captive Portal 请求详情 ===");
  Serial.print("📱 客户端IP: ");
  Serial.println(clientIP);
  Serial.print("📱 请求URI: ");
  Serial.println(uri);
  Serial.print("📱 用户代理: ");
  Serial.println(userAgent);
  Serial.print("📱 请求方法: ");
  Serial.println(server->method() == HTTP_GET ? "GET" : "POST");
  Serial.print("📱 请求头数量: ");
  Serial.println(server->headers());
  
  // 检测设备类型
  bool isAndroid = userAgent.indexOf("Android") >= 0;
  bool isiOS = userAgent.indexOf("iPhone") >= 0 || userAgent.indexOf("iPad") >= 0;
  bool isUC = userAgent.indexOf("UCBrowser") >= 0 || userAgent.indexOf("UCWEB") >= 0;
  
  Serial.print("📱 设备类型: ");
  if (isAndroid) Serial.print("Android ");
  if (isiOS) Serial.print("iOS ");
  if (isUC) Serial.print("UC浏览器 ");
  Serial.println();
  Serial.println("================================");
  
  // 检查是否为Captive Portal检测请求 (支持带UUID后缀的现代Android设备)
  if (uri == "/generate_204" || uri == "/gen_204" || uri.startsWith("/generate_204_")) {
    // Android Captive Portal检测 - 返回非204状态码触发认证页面
    Serial.println("🤖 Android Captive Portal检测 - 返回非204状态触发认证");
    server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server->sendHeader("Pragma", "no-cache");
    server->sendHeader("Expires", "0");
    server->sendHeader("Location", "http://192.168.4.1/config");
    // 返回非204状态码让Android知道需要认证
    server->send(302, "text/html", 
      "<html><head><meta http-equiv='refresh' content='0;url=http://192.168.4.1/config'></head>"
      "<body><script>window.location.href='http://192.168.4.1/config';</script></body></html>");
    return;
  }
  else if (uri == "/redirect" || uri == "/captive-portal") {
    // Android重定向检测
    Serial.println("🤖 Android重定向检测 - 直接重定向");
    server->sendHeader("Location", "http://192.168.4.1/config", true);
    server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server->send(302, "text/html", "");
    return;
  }
  else if (uri == "/hotspot-detect.html" || uri == "/mobile/status.php") {
    // iOS Captive Portal检测 - 返回非期望内容触发认证
    Serial.println("🍎 iOS Captive Portal检测 - 返回非期望内容触发认证");
    server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server->sendHeader("Location", "http://192.168.4.1/config");
    server->send(302, "text/html", 
      "<HTML><HEAD><TITLE>WiFi Authentication Required</TITLE>"
      "<meta http-equiv='refresh' content='0;url=http://192.168.4.1/config'></HEAD>"
      "<BODY>WiFi Authentication Required<script>window.location.href='http://192.168.4.1/config';</script></BODY></HTML>");
    return;
  }
  else if (uri == "/library/test/success.html" || uri == "/success.txt") {
    // iOS其他检测路径
    Serial.println("🍎 iOS成功页面检测 - 返回非期望内容");
    server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server->sendHeader("Location", "http://192.168.4.1/config", true);
    server->send(302, "text/html", 
      "<HTML><HEAD><TITLE>Success</TITLE></HEAD>"
      "<BODY>Success<script>window.location.href='http://192.168.4.1/config';</script></BODY></HTML>");
    return;
  } 
  else if (uri == "/connecttest.txt" || uri == "/msftconnecttest/connecttest.txt") {
    // Windows Captive Portal检测 - 返回非预期内容
    Serial.println("🪟 Windows Captive Portal检测 - 返回非预期内容触发认证");
    server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server->sendHeader("Location", "http://192.168.4.1/config");
    server->send(302, "text/html", 
      "<html><head><meta http-equiv='refresh' content='0;url=http://192.168.4.1/config'></head>"
      "<body>Microsoft Windows Network Connectivity Status Indicator<script>window.location.href='http://192.168.4.1/config';</script></body></html>");
    return;
  }
  else if (uri == "/ncsi.txt") {
    // Windows NCSI检测
    Serial.println("🪟 Windows NCSI检测 - 返回重定向");
    server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server->sendHeader("Location", "http://192.168.4.1/config");
    server->send(302, "text/html", 
      "<html><head><meta http-equiv='refresh' content='0;url=http://192.168.4.1/config'></head></html>");
    return;
  }
  else if (uri.indexOf("msftconnecttest.com") >= 0 || uri.indexOf("msftncsi.com") >= 0) {
    // 微软连接测试
    Serial.println("🪟 微软连接测试 - 重定向到配网页面");
    server->sendHeader("Location", "http://192.168.4.1/config", true);
    server->send(302, "text/plain", "");
    return;
  }
  
  // 对于根路径和其他请求，显示配网页面
  if (uri == "/" || uri == "/index.html" || uri == "/config") {
    Serial.println("📄 显示配网页面");
    handleWiFiConfig();
  } else {
    // 未知路径，重定向到配网页面
    Serial.println("📄 未知路径重定向到配网页面");
    server->sendHeader("Location", "http://192.168.4.1/config", true);
    server->send(302, "text/html", 
      "<html><head><meta http-equiv='refresh' content='0;url=http://192.168.4.1/config'></head>"
      "<body><script>window.location.href='http://192.168.4.1/config';</script></body></html>");
  }
}

void WiFiManager::handleWiFiConfig() {
  String html = F(R"rawliteral(
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
    <meta name="format-detection" content="telephone=no">
    <title>沙画绘图机 - WiFi配置</title>
    <style>
        body { 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            margin: 0; padding: 10px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh; display: flex; align-items: center; justify-content: center;
        }
        .container { 
            background: white; padding: 20px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            max-width: 360px; width: 100%; text-align: center;
        }
        .logo { font-size: 2em; margin-bottom: 10px; }
        .title { color: #333; margin-bottom: 20px; font-size: 1.3em; }
        .mobile-tip { 
            background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 8px; 
            padding: 10px; margin: 15px 0; font-size: 0.9em; color: #856404;
        }
        .form-group { margin: 15px 0; text-align: left; }
        label { display: block; margin-bottom: 5px; color: #555; font-weight: 500; font-size: 0.9em; }
        input { 
            width: 100%; padding: 12px; border: 2px solid #ddd; border-radius: 8px;
            font-size: 16px; box-sizing: border-box; transition: border-color 0.3s;
        }
        input:focus { border-color: #667eea; outline: none; }
        .btn { 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white; border: none; padding: 12px 20px; border-radius: 8px;
            font-size: 16px; cursor: pointer; width: 100%; margin-top: 15px;
            transition: transform 0.2s;
        }
        .btn:hover, .btn:active { transform: translateY(-1px); }
        .btn-small { padding: 8px 16px; font-size: 14px; margin: 5px 0; }
        .status { margin: 15px 0; padding: 10px; border-radius: 5px; font-size: 0.9em; }
        .status.info { background: #d1ecf1; color: #0c5460; }
        .help-text { font-size: 0.8em; color: #666; margin-top: 15px; line-height: 1.4; }
    </style>
</head>
<body>
    <div class="container">
        <div class="logo">🏖️</div>
        <h2 class="title">沙画绘图机配网</h2>
        
        <div class="mobile-tip">
            📱 <strong>连接问题排查：</strong><br>
            • <span id="connectionStatus">正在检测网络状态...</span><br>
            • <span id="browserInfo">正在检测浏览器...</span><br>
            • 请确保已关闭移动数据<br>
            • 当前IP地址: <span id="clientIP">获取中...</span><br>
            • 设备IP: 192.168.4.1
        </div>
        
        <div class="status info">
            请连接您的WiFi网络，设备将自动连接并启动绘图功能
        </div>
        
        <form action="/save" method="POST">
            <div class="form-group">
                <label for="ssid">WiFi名称 (SSID):</label>
                <input type="text" id="ssid" name="ssid" placeholder="请输入WiFi名称" required autocomplete="off">
            </div>
            <div class="form-group">
                <label for="password">WiFi密码:</label>
                <input type="password" id="password" name="password" placeholder="请输入WiFi密码" autocomplete="off">
            </div>
            <button type="submit" class="btn">连接WiFi</button>
        </form>
        
        <div class="help-text">
            <p><strong>📶 WiFi要求：</strong>仅支持2.4GHz网络</p>
            <p><strong>🔧 遇到问题？</strong></p>
            <p>• 确保手机已连接到"沙画绘图机"热点</p>
            <p>• 尝试关闭移动数据后重新访问</p>
            <p>• 可以直接输入: <code>192.168.4.1</code></p>
            <p><a href="/reset" style="color: #dc3545;">清除已保存的WiFi设置</a></p>
        </div>
    </div>
    
    <script>
        // 检测设备类型并给出相应提示
        function detectDevice() {
            const userAgent = navigator.userAgent;
            const isAndroid = /Android/i.test(userAgent);
            const isiOS = /iPhone|iPad/i.test(userAgent);
            const isUC = userAgent.indexOf('UCBrowser') >= 0 || userAgent.indexOf('UCWEB') >= 0 || userAgent.indexOf('UBrowser') >= 0;
            
            // 获取客户端IP信息
            checkNetworkStatus();
            
            // 设备和浏览器检测
            if (isUC) {
                document.getElementById('browserInfo').innerHTML = 
                    '⚠️ 检测到UC浏览器，可能需要<a href="#" onclick="showUCHelp()" style="color: #dc3545;">特殊设置</a>';
                if (isAndroid) {
                    document.getElementById('connectionStatus').innerHTML = '🤖 Android + UC浏览器';
                } else if (isiOS) {
                    document.getElementById('connectionStatus').innerHTML = '🍎 iOS + UC浏览器';
                }
            } else if (isAndroid) {
                document.getElementById('connectionStatus').innerHTML = '🤖 Android设备已检测';
                document.getElementById('browserInfo').innerHTML = '✅ 浏览器兼容 (建议使用Chrome)';
            } else if (isiOS) {
                document.getElementById('connectionStatus').innerHTML = '🍎 iOS设备已检测';
                document.getElementById('browserInfo').innerHTML = '✅ Safari浏览器兼容';
            } else {
                document.getElementById('connectionStatus').innerHTML = '🖥️ 桌面设备已检测';
                document.getElementById('browserInfo').innerHTML = '✅ 浏览器兼容';
            }
            
            // 针对不同系统给出特定提示
            showSystemSpecificTips(isAndroid, isiOS, isUC);
        }
        
        // 显示系统特定提示
        function showSystemSpecificTips(isAndroid, isiOS, isUC) {
            const helpText = document.querySelector('.help-text');
            let systemTips = '';
            
            if (isUC) {
                systemTips = '<p><strong>🔧 UC浏览器用户:</strong></p>' +
                           '<p>• 建议临时使用系统自带浏览器</p>' +
                           '<p>• 或关闭UC的"智能加速"功能</p>';
            } else if (isAndroid) {
                systemTips = '<p><strong>🤖 Android用户:</strong></p>' +
                           '<p>• 确保关闭移动数据</p>' +
                           '<p>• 如无法自动跳转，请手动输入地址</p>' +
                           '<p>• 系统可能提示"无网络连接"，选择"仍要连接"</p>';
            } else if (isiOS) {
                systemTips = '<p><strong>🍎 iOS用户:</strong></p>' +
                           '<p>• 确保关闭蜂窝数据</p>' +
                           '<p>• 可能需要手动打开Safari输入地址</p>' +
                           '<p>• 系统提示"无互联网连接"时选择"使用网络"</p>';
            }
            
            if (systemTips) {
                helpText.innerHTML = systemTips + helpText.innerHTML;
            }
        }
        
        // UC浏览器帮助提示
        function showUCHelp() {
            alert('UC浏览器解决方案：\\n\\n' +
                  '1. 关闭"智能加速"功能\\n' +
                  '2. 关闭"省流量模式"\\n' +
                  '3. 清除浏览器缓存\\n' +
                  '4. 或暂时使用手机自带浏览器\\n\\n' +
                  '如仍有问题，请在地址栏输入：\\n' +
                  'http://192.168.4.1/config');
        }
        
        // 检查网络状态
        function checkNetworkStatus() {
            // 尝试获取客户端IP (通过WebRTC)
            try {
                const pc = new RTCPeerConnection({iceServers: []});
                pc.createDataChannel('');
                pc.createOffer().then(offer => pc.setLocalDescription(offer));
                pc.onicecandidate = (ice) => {
                    if (ice && ice.candidate && ice.candidate.candidate) {
                        const myIP = /([0-9]{1,3}\.){3}[0-9]{1,3}/.exec(ice.candidate.candidate)[0];
                        document.getElementById('clientIP').textContent = myIP;
                        
                        // 检查IP是否在正确范围内
                        if (myIP.startsWith('192.168.4.')) {
                            document.getElementById('connectionStatus').innerHTML = '✅ 网络连接正常';
                        } else {
                            document.getElementById('connectionStatus').innerHTML = '⚠️ 可能未正确连接到热点';
                        }
                        pc.close();
                    }
                };
            } catch(e) {
                document.getElementById('clientIP').textContent = '无法获取';
                document.getElementById('connectionStatus').innerHTML = '⚠️ 网络状态未知';
            }
            
            // 测试到服务器的连接
            fetch('/config', {method: 'HEAD'})
                .then(response => {
                    if (response.ok) {
                        document.getElementById('connectionStatus').innerHTML = '✅ 服务器连接正常';
                    }
                })
                .catch(err => {
                    document.getElementById('connectionStatus').innerHTML = '❌ 服务器连接异常';
                });
        }
        
        // 页面加载完成后检测设备
        window.onload = detectDevice;
        
        // 防止表单重复提交
        document.querySelector('form').addEventListener('submit', function(e) {
            const submitBtn = document.querySelector('button[type="submit"]');
            submitBtn.disabled = true;
            submitBtn.textContent = '连接中...';
        });
        
        // 定期检查连接状态
        setInterval(checkNetworkStatus, 10000);
    </script>
</body>
</html>
)rawliteral");

  // 添加UC浏览器兼容的HTTP头部
  server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  server->sendHeader("Pragma", "no-cache");
  server->sendHeader("Expires", "0");
  server->sendHeader("X-Frame-Options", "DENY");
  server->sendHeader("X-Content-Type-Options", "nosniff");
  
  server->send(200, "text/html", html);
}

void WiFiManager::handleWiFiSave() {
  String ssid = server->arg("ssid");
  String password = server->arg("password");
  
  // 输入验证优化
  if (ssid.length() == 0) {
    sendConfigErrorPage("WiFi名称不能为空");
    return;
  }
  
  if (ssid.length() > 32) {
    sendConfigErrorPage("WiFi名称过长（最大32字符）");
    return;
  }
  
  if (password.length() > 64) {
    sendConfigErrorPage("密码过长（最大64字符）");
    return;
  }
  
  // 验证并清理输入
  ssid.trim();
  password.trim();
  
  logWithTimestamp(String("🌐 配网请求: ") + ssid + ", 密码长度: " + password.length());
  
  // 检查SSID合法性
  if (!validateSSID(ssid)) {
    sendConfigErrorPage("WiFi名称包含不支持的字符");
    return;
  }
  
  // 保存WiFi凭证
  saveWiFiCredentials(ssid, password);
  
  // 发送优化的连接页面
  sendConnectingPage(ssid);
  
  // 非阻塞的连接尝试
  delay(1000);
  handleAsyncWiFiConnection(ssid, password);
}

void WiFiManager::sendConfigErrorPage(const String& errorMsg) {
  StaticJsonDocument<256> doc;
  doc["status"] = "error";
  doc["message"] = errorMsg;
  doc["action"] = "返回配置页面";
  doc["redirect"] = "/config";
  
  String jsonResponse;
  serializeJson(doc, jsonResponse);
  
  server->sendHeader("Cache-Control", "no-cache");
  server->send(400, "application/json", jsonResponse);
}

void WiFiManager::sendConnectingPage(const String& ssid) {
  // 使用PROGMEM存储HTML以节省内存
  const char* html = R"rawliteral(
<!DOCTYPE html>
<html><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>连接中</title>
<style>
body{font-family:-apple-system,sans-serif;margin:0;padding:20px;background:linear-gradient(135deg,#667eea,#764ba2);min-height:100vh;display:flex;align-items:center;justify-content:center}
.container{background:white;padding:30px;border-radius:15px;box-shadow:0 10px 30px rgba(0,0,0,0.2);max-width:400px;width:100%;text-align:center}
.spinner{border:4px solid #f3f3f3;border-top:4px solid #667eea;border-radius:50%;width:40px;height:40px;animation:spin 1s linear infinite;margin:20px auto}
@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
.title{color:#333;margin:15px 0}
.message{color:#666;line-height:1.4;font-size:14px}
</style>
<script>
let countdown=15;
function updateCountdown(){
  document.getElementById('countdown').textContent=countdown;
  if(countdown>0){countdown--;setTimeout(updateCountdown,1000)}
  else{window.location.href='/'}
}
setTimeout(updateCountdown,1000);
</script>
</head><body>
<div class="container">
<div class="spinner"></div>
<h2 class="title">正在连接WiFi</h2>
<p class="message">
连接到: <strong>%SSID%</strong><br>
<span id="countdown">15</span>秒后自动检查状态<br>
<small>连接失败会保持配网模式</small>
</p>
</div></body></html>
)rawliteral";
  
  String response = String(html);
  response.replace("%SSID%", ssid);
  
  server->sendHeader("Cache-Control", "no-cache");
  server->send(200, "text/html", response);
}

bool WiFiManager::validateSSID(const String& ssid) {
  // 基本SSID验证
  if (ssid.length() == 0 || ssid.length() > 32) {
    return false;
  }
  
  // 检查是否包含不可打印字符
  for (int i = 0; i < ssid.length(); i++) {
    char c = ssid.charAt(i);
    if (c < 32 || c > 126) {
      return false;
    }
  }
  
  return true;
}

void WiFiManager::handleAsyncWiFiConnection(const String& ssid, const String& password) {
  // 设置LED指示连接状态
  if (ledManager && ledControlCenter) {
    ledControlCenter->requestStatusChange(LED_WIFI_CONNECTING, "配网连接中");
  }
  
  // 异步尝试连接
  if (connectWiFi(ssid, password)) {
    logWithTimestamp("✅ 配网成功，切换到STA模式");
    
    // 成功连接后的处理
    delay(2000); // 给客户端时间接收响应
    stopConfigPortal();
    startWebServer();
    startWiFiMonitoring();
    
    if (ledManager && ledControlCenter) {
      ledControlCenter->requestStatusChange(LED_WIFI_CONNECTED, "配网成功");
    }
  } else {
    logWithTimestamp("❌ 配网失败，保持AP模式");
    
    if (ledManager && ledControlCenter) {
      ledControlCenter->requestStatusChange(LED_WIFI_FAILED, "配网失败");
    }
  }
}

void WiFiManager::handleWiFiReset() {
  clearWiFiCredentials();
  
  String html = F(R"rawliteral(
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>设置已清除</title>
    <style>
        body { 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            margin: 0; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh; display: flex; align-items: center; justify-content: center;
        }
        .container { 
            background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);
            max-width: 400px; width: 100%; text-align: center;
        }
        .title { color: #333; margin: 20px 0; }
        .btn { 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white; border: none; padding: 12px 30px; border-radius: 8px;
            font-size: 16px; cursor: pointer; text-decoration: none; display: inline-block;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2 class="title">✅ WiFi设置已清除</h2>
        <p>所有保存的WiFi信息已被删除</p>
        <a href="/config" class="btn">重新配置</a>
    </div>
</body>
</html>
)rawliteral");

  server->send(200, "text/html", html);
}

bool WiFiManager::isIPInRange(IPAddress ip) {
  IPAddress softAPIP = WiFi.softAPIP();
  return (ip[0] == softAPIP[0] && ip[1] == softAPIP[1] && ip[2] == softAPIP[2]);
}

// WiFi凭证存储函数
void WiFiManager::saveWiFiCredentials(const String& ssid, const String& password) {
  // 清理和验证输入
  String cleanSSID = ssid;
  String cleanPassword = password;
  cleanSSID.trim();
  cleanPassword.trim();
  
  if (cleanSSID.length() == 0) {
    Serial.println("❌ SSID不能为空");
    return;
  }
  
  // 保存到NVS
  if (preferences.putString("ssid", cleanSSID) && 
      preferences.putString("password", cleanPassword)) {
    Serial.printf("💾 WiFi凭证已保存: SSID='%s', 密码长度=%d\n", 
                  cleanSSID.c_str(), cleanPassword.length());
  } else {
    Serial.println("❌ WiFi凭证保存失败");
  }
}

bool WiFiManager::loadWiFiCredentials() {
  ssid = preferences.getString("ssid", "");
  password = preferences.getString("password", "");
  
  if (ssid.length() > 0) {
    Serial.printf("📖 加载已保存的WiFi: '%s', 密码长度=%d\n", 
                  ssid.c_str(), password.length());
    return true;
  }
  
  Serial.println("📖 未找到已保存的WiFi凭证");
  return false;
}

void WiFiManager::clearWiFiCredentials() {
  preferences.remove("ssid");
  preferences.remove("password");
  ssid = "";
  password = "";
  Serial.println("🗑️ WiFi凭证已清除");
}

bool WiFiManager::startWebServer(int port) {
  if (!isConnected()) {
    logWithTimestamp("❌ 需要先连接WiFi才能启动Web服务器");
    return false;
  }
  
  // 停止现有服务器
  stopWebServer();
  
  server = new WebServer(port);
  
  // 设置优化的路由处理
  setupMainWebRoutes();
  
  // 启用CORS支持和缓存控制
  server->enableCORS(true);
  
  server->begin();
  serverRunning = true;
  
  logWithTimestamp(String("🌐 Web服务器启动成功: http://") + getIP() + ":" + port);
  
  return true;
}

void WiFiManager::setupMainWebRoutes() {
  // 主页路由
  server->on("/", HTTP_GET, [this](){ 
    stats.webRequests++;
    this->handleRoot(); 
  });
  
  // 文件管理路由
  server->on("/upload", HTTP_GET, [this](){ 
    stats.webRequests++;
    this->handleUpload(); 
  });
  server->on("/upload", HTTP_POST, 
    [this](){ stats.webRequests++; }, 
    [this](){ this->handleFileUpload(); }
  );
  server->on("/download", HTTP_POST, [this](){ 
    stats.webRequests++;
    this->handleDownload(); 
  });
  server->on("/files", HTTP_GET, [this](){ 
    stats.webRequests++;
    this->handleFileList(); 
  });
  
  // 状态和控制路由
  server->on("/status", HTTP_GET, [this](){ 
    stats.webRequests++;
    this->handleStatus(); 
  });
  server->on("/control", HTTP_GET, [this](){ 
    stats.webRequests++;
    this->handleControl(); 
  });
  server->on("/control", HTTP_POST, [this](){ 
    stats.webRequests++;
    this->handleControl(); 
  });
  
  // 性能监控路由
  server->on("/stats", HTTP_GET, [this](){ 
    stats.webRequests++;
    server->send(200, "application/json", this->getPerformanceJson());
  });
  server->on("/performance", HTTP_GET, [this](){ 
    stats.webRequests++;
    this->printPerformanceReport();
    server->send(200, "text/plain", "Performance report printed to serial");
  });
  server->on("/reset-stats", HTTP_POST, [this](){ 
    this->resetStats();
    server->send(200, "text/plain", "Statistics reset");
  });
  
  // 系统信息路由
  server->on("/info", HTTP_GET, [this](){ 
    stats.webRequests++;
    StaticJsonDocument<256> doc;
    doc["device"] = "沙画绘图机";
    doc["wifi_ssid"] = WiFi.SSID();
    doc["ip"] = WiFi.localIP().toString();
    doc["signal"] = WiFi.RSSI();
    doc["uptime"] = millis();
    doc["free_memory"] = ESP.getFreeHeap();
    doc["version"] = "1.0.0";
    
    String response;
    serializeJson(doc, response);
    server->send(200, "application/json", response);
  });
  
  // 健康检查路由
  server->on("/health", HTTP_GET, [this](){ 
    server->send(200, "text/plain", "OK");
  });
  
  server->onNotFound([this](){ 
    stats.webRequests++;
    this->handleNotFound(); 
  });
}

void WiFiManager::stopWebServer() {
  if (server && serverRunning) {
    server->stop();
    delete server;
    server = nullptr;
    serverRunning = false;
    Serial.println("🌐 Web服务器已停止");
  }
}

void WiFiManager::handleClient() {
  // 优化的系统状态调试 - 减少字符串分配
  static unsigned long lastDebug = 0;
  unsigned long currentTime = millis();
  
  if (currentTime - lastDebug > STATUS_DEBUG_INTERVAL) {
    logPerformanceMetrics();
    
    if (apMode) {
      int clientCount = WiFi.softAPgetStationNum();
      if (clientCount > 0) {
        logWithTimestamp(String("🔍 连接设备数: ") + clientCount);
        logWithTimestamp("💡 访问调试端点: /debug /simple /ping");
      } else {
        logWithTimestamp("⚠️ 没有设备连接到热点");
      }
    }
    
    lastDebug = currentTime;
  }
  
  // 处理DNS请求（Captive Portal）
  if (dnsServer && apMode) {
    dnsServer->processNextRequest();
  }
  
  // 处理Web服务器请求
  if (server && serverRunning) {
    stats.webRequests++;
    server->handleClient();
  }
  
  // 定期检查WiFi状态和信号强度
  if (wifiMonitoring) {
    checkWiFiStatus();
    updateSignalStats();
  }
}

void WiFiManager::handleRoot() {
  String html = F(R"rawliteral(
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>沙画绘图机控制中心</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { 
            font-family: 'Microsoft YaHei', Arial, sans-serif; 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 10px;
        }
        .container { 
            max-width: 480px; 
            margin: 0 auto; 
            background: rgba(255,255,255,0.95); 
            border-radius: 20px; 
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0,0,0,0.3);
        }
        .header {
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            padding: 20px;
            text-align: center;
        }
        .header h1 { font-size: 1.5em; margin-bottom: 5px; }
        .header p { opacity: 0.9; font-size: 0.9em; }
        
        .section { 
            margin: 15px; 
            padding: 15px; 
            background: white;
            border-radius: 15px; 
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .section h3 { 
            color: #333; 
            margin-bottom: 15px; 
            font-size: 1.1em;
            display: flex;
            align-items: center;
        }
        .section h3::before {
            content: '●';
            color: #4facfe;
            margin-right: 8px;
            font-size: 1.2em;
        }
        
        button { 
            width: 100%;
            padding: 12px;
            margin: 8px 0;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white; 
            border: none; 
            border-radius: 10px; 
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: all 0.3s;
        }
        button:hover { 
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
        button:active { transform: translateY(0); }
        
        input[type="text"], input[type="file"] { 
            width: 100%; 
            padding: 12px; 
            margin: 8px 0;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 14px;
            transition: border-color 0.3s;
        }
        input[type="text"]:focus, input[type="file"]:focus {
            border-color: #4facfe;
            outline: none;
        }
        
        .info-box { 
            background: #f8f9ff; 
            padding: 12px; 
            border-radius: 10px; 
            margin: 10px 0;
            border-left: 4px solid #4facfe;
        }
        .file-item { 
            padding: 10px; 
            margin: 5px 0;
            background: #f8f9ff;
            border-radius: 8px;
            font-size: 14px;
            display: flex;
            align-items: center;
        }
        .file-item::before {
            content: '📄';
            margin-right: 8px;
        }
        
        .wifi-status { 
            padding: 12px; 
            border-radius: 10px; 
            margin: 10px 0;
            font-size: 14px;
        }
        .wifi-connected { 
            background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
            color: #2d5a27;
        }
        .wifi-disconnected { 
            background: linear-gradient(135deg, #ffeaa7 0%, #fab1a0 100%);
            color: #d63031;
        }
        
        .progress-bar { 
            width: 100%; 
            background-color: #e0e0e0; 
            border-radius: 10px; 
            margin: 10px 0;
            overflow: hidden;
        }
        .progress-fill { 
            height: 30px; 
            background: linear-gradient(135deg, #00b894 0%, #00cec9 100%);
            border-radius: 10px; 
            text-align: center; 
            line-height: 30px; 
            color: white; 
            transition: width 0.3s;
            font-weight: bold;
        }
        
        .status-indicator { 
            display: inline-block; 
            width: 10px; 
            height: 10px; 
            border-radius: 50%; 
            margin-right: 8px;
            animation: pulse 2s infinite;
        }
        .status-connected { background-color: #00b894; }
        .status-disconnected { background-color: #e17055; }
        
        @keyframes pulse {
            0% { box-shadow: 0 0 0 0 rgba(0, 184, 148, 0.7); }
            70% { box-shadow: 0 0 0 10px rgba(0, 184, 148, 0); }
            100% { box-shadow: 0 0 0 0 rgba(0, 184, 148, 0); }
        }
        
        .upload-area {
            border: 2px dashed #4facfe;
            border-radius: 10px;
            padding: 20px;
            text-align: center;
            background: #f8f9ff;
            transition: all 0.3s;
        }
        .upload-area:hover {
            border-color: #667eea;
            background: #f0f4ff;
        }
        
        /* 速度滑块样式 */
        input[type="range"] {
            -webkit-appearance: none;
            appearance: none;
            height: 8px;
            background: linear-gradient(135deg, #ddd 0%, #bbb 100%);
            border-radius: 5px;
            outline: none;
        }
        
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 24px;
            height: 24px;
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            border-radius: 50%;
            cursor: pointer;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
        
        input[type="range"]::-moz-range-thumb {
            width: 24px;
            height: 24px;
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            border-radius: 50%;
            cursor: pointer;
            border: none;
            box-shadow: 0 2px 6px rgba(0,0,0,0.3);
        }
        
        /* 数字输入框样式 */
        input[type="number"] {
            text-align: center;
            font-weight: bold;
        }
        
        @media (max-width: 480px) {
            .container { margin: 5px; border-radius: 15px; }
            .section { margin: 10px; padding: 12px; }
            .header { padding: 15px; }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🎨 沙画绘图机</h1>
            <p>ESP32-WROOM-32E 智能控制中心</p>
        </div>
        
        <div class="section">
            <h3>绘图控制</h3>
            <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px;">
                <button onclick="startDrawing()" style="background: linear-gradient(135deg, #00b894 0%, #00cec9 100%);">▶️ 开始绘图</button>
                <button onclick="pauseDrawing()" style="background: linear-gradient(135deg, #fdcb6e 0%, #e17055 100%);">⏸️ 暂停绘图</button>
            </div>
            <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
                <button onclick="stopDrawing()" style="background: linear-gradient(135deg, #e17055 0%, #d63031 100%);">⏹️ 停止绘图</button>
                <button onclick="homeMotors()" style="background: linear-gradient(135deg, #6c5ce7 0%, #74b9ff 100%);">🏠 回零</button>
            </div>
            <div style="display: grid; grid-template-columns: 1fr; gap: 10px; margin-top: 10px;">
                <button onclick="testMaxRadius()" style="background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);">🔍 测量半径轴行程</button>
            </div>
            <div id="drawingStatus" class="info-box" style="margin-top: 10px;">
                <div id="drawingInfo">点击刷新查看绘图状态...</div>
            </div>
            <button onclick="updateDrawingStatus()">🔄 刷新状态</button>
        </div>
        
        <div class="section">
            <h3>速度控制</h3>
            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px; font-weight: bold;">绘图速度系数 (10%-100%)</label>
                <input type="range" id="speedSlider" min="0.1" max="1.0" step="0.1" value="0.3" 
                       style="width: 100%; margin-bottom: 10px;" 
                       oninput="updateSpeedDisplay()">
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <span id="speedDisplay" style="font-weight: bold; color: #4facfe;">30%</span>
                    <button onclick="setDrawingSpeed()" style="width: auto; padding: 8px 16px;">⚡ 设置速度</button>
                </div>
            </div>
            
            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px; font-weight: bold;">最大速度设置 (步/秒)</label>
                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px;">
                    <input type="number" id="thetaSpeed" placeholder="角度轴速度" min="10" max="500" value="150" style="width: 100%;">
                    <input type="number" id="rhoSpeed" placeholder="半径轴速度" min="10" max="500" value="120" style="width: 100%;">
                </div>
                <button onclick="setMaxSpeed()">⚙️ 设置最大速度</button>
            </div>
            
            <button onclick="getSpeedInfo()" style="background: linear-gradient(135deg, #fdcb6e 0%, #e17055 100%);">📊 查看速度信息</button>
            
            <div id="speedInfo" class="info-box" style="margin-top: 10px; display: none;">
                <div id="speedDetails">速度信息将在这里显示...</div>
            </div>
        </div>
        
        <div class="section">
            <h3>网络状态</h3>
            <button onclick="updateWiFiStatus()">🔄 刷新网络状态</button>
            <div id="wifiStatus" class="wifi-status">
                <div id="wifiInfo">点击刷新查看网络状态...</div>
            </div>
        </div>
        
        <div class="section">
            <h3>图案文件</h3>
            <button onclick="loadFileList()">📂 刷新文件列表</button>
            <div id="fileList" class="info-box">点击刷新查看文件...</div>
        </div>
        
        <div class="section">
            <h3>上传图案</h3>
            <div class="upload-area">
                <form action="/upload" method="POST" enctype="multipart/form-data">
                    <p style="margin-bottom: 10px;">📁 选择 .thr 图案文件</p>
                    <input type="file" name="file" accept=".thr" required>
                    <button type="submit">⬆️ 上传文件</button>
                </form>
            </div>
        </div>
        
        <div class="section">
            <h3>网络下载</h3>
            <input type="text" id="downloadUrl" placeholder="🌐 输入图案文件网址" value="https://example.com/pattern.thr">
            <input type="text" id="downloadName" placeholder="💾 保存文件名" value="downloaded.thr">
            <button onclick="downloadFile()">⬇️ 下载文件</button>
            <div id="downloadProgress" class="progress-bar" style="display: none;">
                <div id="progressFill" class="progress-fill" style="width: 0%;">0%</div>
            </div>
        </div>
        
        <div class="section">
            <h3>默认图案包</h3>
            <button onclick="downloadDefaults()">📦 下载默认图案包</button>
            <div class="info-box">
                <p>包含：圆形、螺旋、花朵、心形、方形 (5个文件)</p>
            </div>
            <div id="defaultsProgress" class="progress-bar" style="display: none;">
                <div id="defaultsProgressFill" class="progress-fill" style="width: 0%;">0%</div>
            </div>
        </div>
    </div>

    <script>
        function loadFileList() {
            fetch('/files')
                .then(response => response.json())
                .then(data => {
                    const fileList = document.getElementById('fileList');
                    if (data.files && data.files.length > 0) {
                        fileList.innerHTML = data.files.map(file => 
                            '<div class="file-item">' + file.name + ' (' + file.size + ' 字节)</div>'
                        ).join('');
                    } else {
                        fileList.innerHTML = '<div class="file-item">❌ 未找到文件</div>';
                    }
                })
                .catch(err => {
                    document.getElementById('fileList').innerHTML = '<div class="file-item">❌ 加载文件列表失败</div>';
                });
        }
        
        function updateWiFiStatus() {
            fetch('/status')
                .then(response => response.json())
                .then(data => {
                    const wifiStatus = document.getElementById('wifiStatus');
                    const wifiInfo = document.getElementById('wifiInfo');
                    if (data.connected) {
                        wifiStatus.className = 'wifi-status wifi-connected';
                        wifiInfo.innerHTML = `
                            <div><span class="status-indicator status-connected"></span>📶 WiFi 已连接</div>
                            <div>🌐 IP地址: ${data.ip}</div>
                            <div>📡 信号强度: ${data.signal} dBm</div>
                            <div>📋 网络名称: ${data.ssid}</div>
                        `;
                    } else {
                        wifiStatus.className = 'wifi-status wifi-disconnected';
                        wifiInfo.innerHTML = '<div><span class="status-indicator status-disconnected"></span>❌ WiFi 未连接</div>';
                    }
                })
                .catch(err => {
                    document.getElementById('wifiInfo').innerHTML = '<div>❌ 检查网络状态失败</div>';
                });
        }
        
        function downloadFile() {
            const url = document.getElementById('downloadUrl').value;
            const name = document.getElementById('downloadName').value;
            
            if (!url || !name) {
                alert('请输入网址和文件名');
                return;
            }
            
            const progressDiv = document.getElementById('downloadProgress');
            const progressFill = document.getElementById('progressFill');
            progressDiv.style.display = 'block';
            progressFill.style.width = '0%';
            progressFill.textContent = '下载中...';
            
            fetch('/download', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ url: url, filename: name })
            })
            .then(response => response.json())
            .then(data => {
                progressFill.style.width = '100%';
                progressFill.textContent = '✅ 完成';
                setTimeout(() => {
                    progressDiv.style.display = 'none';
                }, 2000);
                
                alert(data.message);
                if (data.success) loadFileList();
            })
            .catch(err => {
                progressDiv.style.display = 'none';
                alert('下载失败: ' + err);
            });
        }
        
        function downloadDefaults() {
            const progressDiv = document.getElementById('defaultsProgress');
            const progressFill = document.getElementById('defaultsProgressFill');
            progressDiv.style.display = 'block';
            progressFill.textContent = '正在下载...';
            
            let progress = 0;
            const progressInterval = setInterval(() => {
                progress += 20;
                progressFill.style.width = progress + '%';
                progressFill.textContent = progress + '%';
                if (progress >= 100) {
                    clearInterval(progressInterval);
                }
            }, 500);
            
            fetch('/download', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ url: 'defaults', filename: 'pack' })
            })
            .then(response => response.json())
            .then(data => {
                clearInterval(progressInterval);
                progressFill.style.width = '100%';
                progressFill.textContent = '✅ 完成';
                setTimeout(() => {
                    progressDiv.style.display = 'none';
                }, 2000);
                
                alert(data.message);
                if (data.success) loadFileList();
            })
            .catch(err => {
                clearInterval(progressInterval);
                progressDiv.style.display = 'none';
                alert('下载失败: ' + err);
            });
        }
        
        function updateDrawingStatus() {
            fetch('/control?action=status')
                .then(response => response.json())
                .then(data => {
                    const drawingInfo = document.getElementById('drawingInfo');
                    if (data.success) {
                        drawingInfo.innerHTML = `
                            <div>🎨 绘图状态: ${data.state}</div>
                            <div>📊 进度: ${data.progress}%</div>
                            <div>📁 当前图案: ${data.pattern}</div>
                        `;
                    } else {
                        drawingInfo.innerHTML = '<div>❌ 获取状态失败</div>';
                    }
                })
                .catch(err => {
                    document.getElementById('drawingInfo').innerHTML = '<div>❌ 状态查询错误</div>';
                });
        }
        
        function startDrawing() {
            fetch('/control?action=start', { method: 'POST' })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                    updateDrawingStatus();
                })
                .catch(err => alert('启动绘图失败: ' + err));
        }
        
        function pauseDrawing() {
            fetch('/control?action=pause', { method: 'POST' })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                    updateDrawingStatus();
                })
                .catch(err => alert('暂停绘图失败: ' + err));
        }
        
        function stopDrawing() {
            fetch('/control?action=stop', { method: 'POST' })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                    updateDrawingStatus();
                })
                .catch(err => alert('停止绘图失败: ' + err));
        }
        
        function updateSpeedDisplay() {
            const slider = document.getElementById('speedSlider');
            const display = document.getElementById('speedDisplay');
            const percentage = Math.round(slider.value * 100);
            display.textContent = percentage + '%';
        }
        
        function setDrawingSpeed() {
            const speed = document.getElementById('speedSlider').value;
            
            fetch('/control?action=setspeed&value=' + speed, { method: 'POST' })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                    if (data.success) {
                        updateDrawingStatus();
                    }
                })
                .catch(err => alert('设置速度失败: ' + err));
        }
        
        function setMaxSpeed() {
            const thetaSpeed = document.getElementById('thetaSpeed').value;
            const rhoSpeed = document.getElementById('rhoSpeed').value;
            
            if (!thetaSpeed || !rhoSpeed) {
                alert('请输入角度轴和半径轴速度');
                return;
            }
            
            if (thetaSpeed < 10 || thetaSpeed > 500 || rhoSpeed < 10 || rhoSpeed > 500) {
                alert('速度范围: 10-500 步/秒');
                return;
            }
            
            fetch('/control?action=setmaxspeed&theta=' + thetaSpeed + '&rho=' + rhoSpeed, { method: 'POST' })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                })
                .catch(err => alert('设置最大速度失败: ' + err));
        }
        
        function getSpeedInfo() {
            fetch('/control?action=speedinfo')
                .then(response => response.json())
                .then(data => {
                    const speedInfo = document.getElementById('speedInfo');
                    const speedDetails = document.getElementById('speedDetails');
                    
                    if (data.success) {
                        speedDetails.innerHTML = data.info;
                        speedInfo.style.display = 'block';
                    } else {
                        speedDetails.innerHTML = '❌ 获取速度信息失败';
                        speedInfo.style.display = 'block';
                    }
                })
                .catch(err => {
                    const speedInfo = document.getElementById('speedInfo');
                    const speedDetails = document.getElementById('speedDetails');
                    speedDetails.innerHTML = '❌ 查询速度信息错误';
                    speedInfo.style.display = 'block';
                });
        }
        
        function homeMotors() {
            if (confirm('确定要执行回零操作吗？这会移动电机到初始位置。')) {
                fetch('/control?action=home', { method: 'POST' })
                    .then(response => response.json())
                    .then(data => {
                        alert(data.message);
                        updateDrawingStatus();
                    })
                    .catch(err => alert('回零操作失败: ' + err));
            }
        }
        
        function testMaxRadius() {
            if (confirm('开始半径轴行程测试？\\n\\n注意：\\n1. 请确保已完成回零\\n2. 测试过程中请在串口监视器中操作\\n3. 输入命令控制半径轴移动\\n4. 观察机械限位避免损坏')) {
                fetch('/control?action=testradius', { method: 'POST' })
                    .then(response => response.json())
                    .then(data => {
                        if (data.success) {
                            alert(data.message + '\\n\\n请打开 PlatformIO 的串口监视器进行交互操作！');
                        } else {
                            alert(data.message);
                        }
                    })
                    .catch(err => alert('测试启动失败: ' + err));
            }
        }
        
        window.onload = function() {
            loadFileList();
            updateWiFiStatus();
            updateDrawingStatus();
            setInterval(updateWiFiStatus, 30000);
            setInterval(updateDrawingStatus, 5000); // 每5秒更新绘图状态
        };
    </script>
</body>
</html>
)rawliteral");
  
  server->send(200, "text/html", html);
}

void WiFiManager::handleUpload() {
  server->send(200, "text/plain", "请使用主页面上传文件");
}

void WiFiManager::handleFileUpload() {
  HTTPUpload& upload = server->upload();
  static File uploadFile;
  
  if (upload.status == UPLOAD_FILE_START) {
    String filename = "/" + upload.filename;
    Serial.print("📤 开始上传文件: ");
    Serial.println(filename);
    
    uploadFile = SD.open(filename, FILE_WRITE);
    if (!uploadFile) {
      Serial.println("❌ 无法创建上传文件");
      server->send(500, "text/plain", "文件创建失败");
      return;
    }
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (uploadFile) {
      uploadFile.write(upload.buf, upload.currentSize);
    }
  } else if (upload.status == UPLOAD_FILE_END) {
    if (uploadFile) {
      uploadFile.close();
      Serial.print("✅ 文件上传完成: ");
      Serial.print(upload.totalSize);
      Serial.println(" bytes");
      
      server->sendHeader("Location", "/");
      server->send(303);
    } else {
      server->send(500, "text/plain", "上传失败");
    }
  }
}

void WiFiManager::handleDownload() {
  if (!server->hasArg("plain")) {
    sendJsonResponse(400, "缺少JSON数据");
    return;
  }
  
  DynamicJsonDocument doc(1024);
  deserializeJson(doc, server->arg("plain"));
  
  String url = doc["url"];
  String filename = doc["filename"];
  
  if (url.length() == 0 || filename.length() == 0) {
    sendJsonResponse(400, "缺少URL或文件名");
    return;
  }
  
  // 特殊处理：下载默认图案包
  if (url == "defaults") {
    Serial.println("📦 Web请求: 下载默认图案包");
    downloadDefaultPatterns();
    sendJsonResponse(200, "默认图案包下载完成");
    return;
  }
  
  Serial.print("📥 开始下载: ");
  Serial.println(url);
  
  if (downloadFile(url, filename)) {
    sendJsonResponse(200, "文件下载成功: " + filename);
  } else {
    sendJsonResponse(500, "文件下载失败");
  }
}

void WiFiManager::handleFileList() {
  if (!patternLoader->isSDReady()) {
    sendJsonResponse(500, "SD卡未就绪");
    return;
  }
  
  std::vector<String> files = patternLoader->listPatternFiles();
  
  DynamicJsonDocument doc(2048);
  JsonArray fileArray = doc.createNestedArray("files");
  
  File root = SD.open("/");
  while (true) {
    File entry = root.openNextFile();
    if (!entry) break;
    
    if (!entry.isDirectory()) {
      JsonObject fileObj = fileArray.createNestedObject();
      fileObj["name"] = entry.name();
      fileObj["size"] = entry.size();
    }
    entry.close();
  }
  root.close();
  
  String response;
  serializeJson(doc, response);
  server->send(200, "application/json", response);
}

void WiFiManager::handleNotFound() {
  server->send(404, "text/plain", "页面未找到");
}

void WiFiManager::handleStatus() {
  DynamicJsonDocument doc(512);
  
  doc["connected"] = isConnected();
  doc["status"] = getWiFiStatusString();
  
  if (isConnected()) {
    doc["ip"] = getIP();
    doc["ssid"] = WiFi.SSID();
    doc["signal"] = getSignalStrength();
    doc["mac"] = WiFi.macAddress();
  }
  
  String response;
  serializeJson(doc, response);
  server->send(200, "application/json", response);
}

void WiFiManager::handleControl() {
  DynamicJsonDocument doc(512);
  String action = server->arg("action");
  
  // 注意：绘图功能已迁移到MotionController，通过串口命令控制
  
  if (action == "status") {
    // 提供基本状态信息
    doc["success"] = true;
    doc["state"] = "⏸️ 就绪待机";
    doc["progress"] = 0;
    doc["pattern"] = "请使用串口命令控制绘图";
    doc["message"] = "绘图功能已迁移到MotionController";
    
  } else if (action == "start") {
    doc["success"] = false;
    doc["message"] = "请使用串口命令 'pattern <文件名>' 开始绘图";
    
  } else if (action == "pause") {
    doc["success"] = false;
    doc["message"] = "请使用串口命令控制暂停/恢复功能";
    
  } else if (action == "stop") {
    doc["success"] = false;
    doc["message"] = "请使用串口命令 'stop' 停止绘图";
    
  } else if (action == "home") {
    // 检查是否可以执行回零操作
    if (motionController->isMovingNow()) {
      doc["success"] = false;
      doc["message"] = "⚠️ 电机正在运动中，无法执行归零操作";
    } else {
      motionController->homeMotorsWithCompensation();  // 使用MotionController统一归零
      
      // 🔥 关键修复：HOME命令执行后清除暂停状态，强制重新开始绘图
      extern int pausedAtIndex;
      pausedAtIndex = 0;
      Serial.println("🔄 WiFi HOME操作完成，暂停状态已清除，下次start将重新开始绘图");
      
      doc["success"] = true;
      doc["message"] = "🏠 MotionController统一归零操作已开始";
    }
    
  } else if (action == "setspeed") {
    String speedStr = server->arg("value");
    float speed = speedStr.toFloat();
    
    if (speed >= 0.1 && speed <= 1.0) {
      motionController->setMaxSpeed(speed * 400);  // 转换为步/秒 (400是基础速度)
      doc["success"] = true;
      doc["message"] = "⚡ 绘图速度已设置为: " + String((int)(speed * 100)) + "%";
    } else {
      doc["success"] = false;
      doc["message"] = "❌ 速度系数范围: 0.1-1.0 (10%-100%)";
    }
    
  } else if (action == "setmaxspeed") {
    String thetaStr = server->arg("theta");
    String rhoStr = server->arg("rho");
    int thetaSpeed = thetaStr.toInt();
    int rhoSpeed = rhoStr.toInt();
    
    if (thetaSpeed >= 10 && thetaSpeed <= 500 && rhoSpeed >= 10 && rhoSpeed <= 500) {
      motionController->setMaxSpeed((thetaSpeed + rhoSpeed) / 2);  // 使用平均值作为统一速度
      doc["success"] = true;
      doc["message"] = "⚙️ 最大速度已设置为: " + String((thetaSpeed + rhoSpeed) / 2) + " 步/秒 (统一管理)";
    } else {
      doc["success"] = false;
      doc["message"] = "❌ 速度范围: 10-500步/秒";
    }
    
  } else if (action == "speedinfo") {
    // 获取速度信息并格式化为HTML
    String speedInfo = "";
    speedInfo += "<div style='font-size: 14px;'>";
    speedInfo += "<div><strong>📊 当前速度配置</strong></div>";
    speedInfo += "<div style='margin: 8px 0;'>⚡ 绘图速度系数: 正在获取...</div>";
    speedInfo += "<div style='margin: 8px 0;'>🔧 基础最大速度: 正在获取...</div>";
    speedInfo += "<div style='margin: 8px 0;'>🏃 实际运行速度: 正在获取...</div>";
    speedInfo += "<div style='margin-top: 10px; font-size: 12px; color: #666;'>";
    speedInfo += "💡 提示: 速度过快可能影响绘图精度";
    speedInfo += "</div>";
    speedInfo += "</div>";
    
    doc["success"] = true;
    doc["info"] = speedInfo;
    
  } else if (action == "testradius") {
    // 半径轴行程测试
    if (!motionController->isHomed()) {
      doc["success"] = false;
      doc["message"] = "❌ 请先完成回零操作";
    } else {
      // 测试功能现在由MotionController提供
      doc["success"] = true;
      doc["message"] = "📏 半径轴测试功能已整合到MotionController";
      doc["success"] = true;
      doc["message"] = "🔍 半径轴测试已启动，请查看串口监视器进行交互操作";
    }
    
  } else {
    doc["success"] = false;
    doc["message"] = "❌ 未知的控制命令";
  }
  
  String response;
  serializeJson(doc, response);
  server->send(200, "application/json", response);
}

bool WiFiManager::downloadFile(const String& url, const String& filename) {
  if (!isConnected()) {
    Serial.println("❌ WiFi未连接");
    return false;
  }
  
  HTTPClient http;
  http.begin(url);
  
  int httpResponseCode = http.GET();
  
  if (httpResponseCode == HTTP_CODE_OK) {
    String fullPath = "/" + filename;
    File file = SD.open(fullPath, FILE_WRITE);
    
    if (!file) {
      Serial.println("❌ 无法创建文件");
      http.end();
      return false;
    }
    
    // 获取文件大小
    int contentLength = http.getSize();
    Serial.print("文件大小: ");
    Serial.print(contentLength);
    Serial.println(" bytes");
    
    // 分块下载
    WiFiClient* stream = http.getStreamPtr();
    uint8_t buff[1024] = { 0 };
    int downloadedBytes = 0;
    
    while (http.connected() && (contentLength > 0 || contentLength == -1)) {
      size_t size = stream->available();
      if (size) {
        int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
        file.write(buff, c);
        downloadedBytes += c;
        
        if (contentLength > 0) {
          Serial.print("下载进度: ");
          Serial.print((downloadedBytes * 100) / contentLength);
          Serial.println("%");
        }
        
        if (contentLength > 0) {
          contentLength -= c;
        }
      }
      yield(); // 避免看门狗重置
    }
    
    file.close();
    http.end();
    
    Serial.print("✅ 下载完成: ");
    Serial.println(fullPath);
    return true;
  } else {
    Serial.print("❌ HTTP错误: ");
    Serial.println(httpResponseCode);
    http.end();
    return false;
  }
}

bool WiFiManager::downloadPattern(const String& url, const String& filename) {
  return downloadFile(url, filename);
}

bool WiFiManager::downloadPatternWithProgress(const String& url, const String& filename, 
                                               std::function<void(int)> progressCallback) {
  if (!isConnected()) {
    logWithTimestamp("❌ WiFi未连接，无法下载");
    return false;
  }
  
  logWithTimestamp(String("📥 开始下载: ") + url);
  
  HTTPClient http;
  http.begin(url);
  http.setTimeout(30000); // 30秒超时
  http.setUserAgent("SandDrawingMachine/1.0");
  http.addHeader("Accept", "*/*");
  
  unsigned long startTime = millis();
  int httpResponseCode = http.GET();
  
  if (httpResponseCode == HTTP_CODE_OK) {
    String fullPath = "/" + filename;
    File file = SD.open(fullPath, FILE_WRITE);
    
    if (!file) {
      logWithTimestamp("❌ 无法创建文件: " + fullPath);
      http.end();
      return false;
    }
    
    // 获取文件大小
    int contentLength = http.getSize();
    logWithTimestamp(String("📄 文件大小: ") + contentLength + " bytes");
    
    // 优化的分块下载
    WiFiClient* stream = http.getStreamPtr();
    const size_t bufferSize = 2048; // 增大缓冲区
    uint8_t* buff = new uint8_t[bufferSize];
    int downloadedBytes = 0;
    int lastReportedProgress = -1;
    unsigned long lastYield = millis();
    
    while (http.connected() && (contentLength > 0 || contentLength == -1)) {
      size_t size = stream->available();
      if (size) {
        size_t readSize = min(size, bufferSize);
        int c = stream->readBytes(buff, readSize);
        
        if (c > 0) {
          file.write(buff, c);
          downloadedBytes += c;
          stats.totalDataTransferred += c;
          
          if (contentLength > 0) {
            int progress = (downloadedBytes * 100) / contentLength;
            if (progress != lastReportedProgress && (progress % 5 == 0 || progress == 100)) {
              logWithTimestamp(String("📊 下载进度: ") + progress + "%");
              lastReportedProgress = progress;
              
              // 调用进度回调函数
              if (progressCallback) {
                progressCallback(progress);
              }
            }
          }
          
          if (contentLength > 0) {
            contentLength -= c;
          }
        }
      }
      
      // 定期yield避免看门狗重置
      unsigned long currentTime = millis();
      if (currentTime - lastYield > 100) {
        yield();
        lastYield = currentTime;
      }
    }
    
    delete[] buff;
    file.close();
    http.end();
    
    unsigned long downloadTime = millis() - startTime;
    float speed = downloadedBytes / (downloadTime / 1000.0f);
    
    logWithTimestamp(String("✅ 下载完成: ") + fullPath);
    logWithTimestamp(String("📊 下载统计: ") + downloadedBytes + " bytes, " + 
                    downloadTime + "ms, " + (speed/1024) + " KB/s");
    
    return true;
  } else {
    logWithTimestamp(String("❌ HTTP错误: ") + httpResponseCode);
    
    String errorDesc = getHttpErrorDescription(httpResponseCode);
    logWithTimestamp(String("🔍 错误详情: ") + errorDesc);
    
    http.end();
    return false;
  }
}

String WiFiManager::getHttpErrorDescription(int code) {
  switch (code) {
    case -1: return "连接失败";
    case -2: return "发送头部失败";
    case -3: return "发送负载失败";
    case -4: return "没有响应流";
    case -5: return "没有HTTP响应";
    case -6: return "读取超时";
    case -7: return "数据大小不匹配";
    case -8: return "内存不足";
    case -9: return "编码错误";
    case -10: return "流写入错误";
    case -11: return "连接被拒绝";
    case 400: return "请求错误";
    case 401: return "未授权";
    case 403: return "访问被拒绝";
    case 404: return "文件未找到";
    case 408: return "请求超时";
    case 500: return "服务器内部错误";
    case 502: return "网关错误";
    case 503: return "服务不可用";
    case 504: return "网关超时";
    default: return String("未知错误(") + code + ")";
  }
}

void WiFiManager::startWiFiMonitoring() {
  if (!wifiMonitoring) {
    wifiMonitoring = true;
    lastWiFiCheck = millis();
    reconnectAttempts = 0;
    currentRetryDelay = 1000; // 重置重试延迟
    logWithTimestamp("📡 启动WiFi状态监控");
    
    // 如果当前已连接，记录连接开始时间
    if (isConnected() && stats.currentConnectionStart == 0) {
      stats.currentConnectionStart = millis();
    }
  }
}

void WiFiManager::stopWiFiMonitoring() {
  if (wifiMonitoring) {
    wifiMonitoring = false;
    
    // 记录最后的连接时长
    if (stats.currentConnectionStart > 0 && isConnected()) {
      unsigned long connectionTime = millis() - stats.currentConnectionStart;
      if (connectionTime > stats.longestConnectionTime) {
        stats.longestConnectionTime = connectionTime;
      }
    }
    
    logWithTimestamp("📡 停止WiFi状态监控");
  }
}

bool WiFiManager::checkWiFiStatus() {
  if (!wifiMonitoring) return isConnected();
  
  unsigned long currentTime = millis();
  if (currentTime - lastWiFiCheck >= WIFI_CHECK_INTERVAL) {
    lastWiFiCheck = currentTime;
    
    bool currentStatus = (WiFi.status() == WL_CONNECTED);
    
    if (wifiConnected && !currentStatus) {
      // WiFi连接丢失
      logWithTimestamp("⚠️ WiFi连接丢失，启动重连机制");
      wifiConnected = false;
      stats.totalDisconnections++;
      
      // 记录连接时长
      if (stats.currentConnectionStart > 0) {
        unsigned long connectionTime = currentTime - stats.currentConnectionStart;
        if (connectionTime > stats.longestConnectionTime) {
          stats.longestConnectionTime = connectionTime;
        }
        stats.currentConnectionStart = 0;
      }
      
      handleWiFiReconnect();
    } else if (!wifiConnected && currentStatus) {
      // WiFi重新连接成功
      logWithTimestamp("🔄 WiFi重新连接成功");
      wifiConnected = true;
      reconnectAttempts = 0;
      stats.currentConnectionStart = currentTime;
      updateSignalStats();
    }
  }
  
  return isConnected();
}

void WiFiManager::handleWiFiReconnect() {
  unsigned long currentTime = millis();
  
  // 检查是否需要等待重试间隔
  if (lastRetryTime > 0 && (currentTime - lastRetryTime) < currentRetryDelay) {
    return; // 还在等待重试间隔
  }
  
  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
    logWithTimestamp("❌ WiFi重连次数已达上限，启动配网模式");
    
    // 启动配网模式以供用户重新配置
    if (!apMode) {
      stopWebServer();
      startConfigPortal();
    }
    return;
  }
  
  reconnectAttempts++;
  lastRetryTime = currentTime;
  
  logWithTimestamp(String("🔄 尝试重新连接WiFi (") + reconnectAttempts + 
                  "/" + MAX_RECONNECT_ATTEMPTS + ") 延迟: " + currentRetryDelay + "ms");
  
  // LED状态指示
  if (ledManager && ledControlCenter) {
    ledControlCenter->requestStatusChange(LED_WIFI_CONNECTING, "WiFi重连中");
  }
  
  // 智能重连策略
  WiFi.disconnect(true);
  delay(500);
  
  // 尝试不同的连接参数
  if (reconnectAttempts == 1) {
    // 第一次重连：标准连接
    WiFi.begin(ssid.c_str(), password.c_str());
  } else if (reconnectAttempts == 2) {
    // 第二次重连：指定信道和BSSID（如果可用）
    WiFi.begin(ssid.c_str(), password.c_str());
  } else {
    // 后续重连：使用更保守的设置
    WiFi.begin(ssid.c_str(), password.c_str());
    WiFi.setSleep(false); // 禁用WiFi睡眠
  }
  
  // 等待连接结果
  int attempts = 0;
  const int maxConnectAttempts = 15; // 减少等待时间
  
  while (WiFi.status() != WL_CONNECTED && attempts < maxConnectAttempts) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    wifiConnected = true;
    reconnectAttempts = 0;
    currentRetryDelay = 1000; // 重置重试延迟
    stats.currentConnectionStart = millis();
    updateConnectionStats(true);
    
    logWithTimestamp("✅ WiFi重连成功");
    
    if (ledManager && ledControlCenter) {
      ledControlCenter->requestStatusChange(LED_WIFI_CONNECTED, "WiFi重连成功");
    }
    
    // 重新启动Web服务器（如果需要）
    if (!serverRunning && !apMode) {
      startWebServer();
    }
  } else {
    Serial.println();
    // 指数退避策略
    currentRetryDelay = min(currentRetryDelay * (int)RETRY_BACKOFF_MULTIPLIER, 30000);
    logWithTimestamp(String("❌ WiFi重连失败，下次重试延迟: ") + currentRetryDelay + "ms");
    
    if (ledManager && ledControlCenter) {
      ledControlCenter->requestStatusChange(LED_WIFI_FAILED, "WiFi重连失败");
    }
    Serial.println("❌ WiFi重连失败");
  }
}

void WiFiManager::printNetworkInfo() {
  Serial.println("🌐 网络信息详情:");
  if (isConnected()) {
    Serial.print("  SSID: ");
    Serial.println(WiFi.SSID());
    Serial.print("  IP地址: ");
    Serial.println(WiFi.localIP());
    Serial.print("  子网掩码: ");
    Serial.println(WiFi.subnetMask());
    Serial.print("  网关: ");
    Serial.println(WiFi.gatewayIP());
    Serial.print("  DNS: ");
    Serial.println(WiFi.dnsIP());
    Serial.print("  MAC地址: ");
    Serial.println(WiFi.macAddress());
    Serial.print("  信号强度: ");
    Serial.print(WiFi.RSSI());
    Serial.println(" dBm");
    Serial.print("  信号质量: ");
    int rssi = WiFi.RSSI();
    String quality = "优秀";
    if (rssi < -80) quality = "较差";
    else if (rssi < -70) quality = "一般";
    else if (rssi < -60) quality = "良好";
    Serial.println(quality);
  } else {
    Serial.println("  状态: 未连接");
  }
}

String WiFiManager::getWiFiStatusString() {
  switch (WiFi.status()) {
    case WL_CONNECTED: return "已连接";
    case WL_NO_SSID_AVAIL: return "SSID不可用";
    case WL_CONNECT_FAILED: return "连接失败";
    case WL_CONNECTION_LOST: return "连接丢失";
    case WL_DISCONNECTED: return "已断开";
    case WL_IDLE_STATUS: return "空闲状态";
    default: return "未知状态";
  }
}

int WiFiManager::getSignalStrength() {
  return WiFi.RSSI();
}

void WiFiManager::sendJsonResponse(int code, const String& message) {
  DynamicJsonDocument doc(512);
  doc["success"] = (code == 200);
  doc["message"] = message;
  
  String response;
  serializeJson(doc, response);
  server->send(code, "application/json", response);
}

void WiFiManager::printStatus() {
  Serial.println("📡 WiFi状态信息:");
  Serial.println("==================");
  Serial.print("连接状态: ");
  Serial.println(getWiFiStatusString());
  
  if (isConnected()) {
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());
    Serial.print("IP地址: ");
    Serial.println(getIP());
    Serial.print("信号强度: ");
    Serial.print(getSignalStrength());
    Serial.println(" dBm");
    Serial.print("MAC地址: ");
    Serial.println(WiFi.macAddress());
  }
  
  Serial.print("Web服务器: ");
  Serial.println(serverRunning ? "运行中" : "已停止");
  Serial.print("WiFi监控: ");
  Serial.println(wifiMonitoring ? "启用" : "禁用");
  Serial.println("==================");
}

void WiFiManager::downloadDefaultPatterns() {
  Serial.println("📦 开始下载默认图案包...");
  
  // 默认图案包的URL和文件名
  struct DefaultPattern {
    String url;
    String filename;
    String description;
  };
  
  DefaultPattern patterns[] = {
    {"https://raw.githubusercontent.com/esp32-sand-art/patterns/main/circle.thr", "circle.thr", "圆形图案"},
    {"https://raw.githubusercontent.com/esp32-sand-art/patterns/main/spiral.thr", "spiral.thr", "螺旋图案"},
    {"https://raw.githubusercontent.com/esp32-sand-art/patterns/main/flower.thr", "flower.thr", "花朵图案"},
    {"https://raw.githubusercontent.com/esp32-sand-art/patterns/main/heart.thr", "heart.thr", "心形图案"},
    {"https://raw.githubusercontent.com/esp32-sand-art/patterns/main/square.thr", "square.thr", "方形图案"}
  };
  
  int totalPatterns = sizeof(patterns) / sizeof(patterns[0]);
  int successCount = 0;
  
  for (int i = 0; i < totalPatterns; i++) {
    Serial.print("下载 ");
    Serial.print(patterns[i].description);
    Serial.print(" (");
    Serial.print(i + 1);
    Serial.print("/");
    Serial.print(totalPatterns);
    Serial.println(")...");
    
    if (downloadFile(patterns[i].url, patterns[i].filename)) {
      successCount++;
      Serial.print("✅ ");
      Serial.print(patterns[i].filename);
      Serial.println(" 下载成功");
    } else {
      Serial.print("❌ ");
      Serial.print(patterns[i].filename);
      Serial.println(" 下载失败");
    }
    
    delay(1000); // 避免过快请求
  }
  
  Serial.println("📦 默认图案包下载完成!");
  Serial.print("成功: ");
  Serial.print(successCount);
  Serial.print("/");
  Serial.print(totalPatterns);
  Serial.println(" 个文件");
}

void WiFiManager::handleNetworkTest() {
  IPAddress clientIP = server->client().remoteIP();
  
  DynamicJsonDocument doc(512);
  doc["server_ip"] = WiFi.softAPIP().toString();
  doc["client_ip"] = clientIP.toString();
  doc["ap_clients"] = WiFi.softAPgetStationNum();
  doc["server_running"] = serverRunning;
  doc["dns_running"] = (dnsServer != nullptr);
  doc["memory_free"] = ESP.getFreeHeap();
  doc["uptime"] = millis();
  
  String response;
  serializeJson(doc, response);
  
  Serial.print("🧪 网络测试请求 - 客户端IP: ");
  Serial.println(clientIP);
  
  server->send(200, "application/json", response);
}

// ==================== 新增辅助方法实现 ====================

bool WiFiManager::configureAPMode() {
  // 确保先断开现有连接
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  delay(WIFI_DISCONNECT_DELAY);
  WiFi.mode(WIFI_AP);
  
  bool result;
  if (apPassword.length() > 0) {
    result = WiFi.softAP(apSSID.c_str(), apPassword.c_str());
  } else {
    result = WiFi.softAP(apSSID.c_str());
  }
  
  if (!result) {
    logWithTimestamp("❌ 热点启动失败");
    return false;
  }
  
  delay(AP_CONFIG_DELAY);
  
  // 配置AP IP地址
  IPAddress apIP = getAPIP();
  IPAddress gateway = getAPGateway();
  IPAddress subnet = getAPSubnet();
  
  bool configResult = WiFi.softAPConfig(apIP, gateway, subnet);
  logWithTimestamp(String("📡 AP IP配置: ") + (configResult ? "成功" : "失败"));
  
  // 验证IP配置
  delay(1000);
  IPAddress actualIP = WiFi.softAPIP();
  
  if (actualIP != apIP) {
    logWithTimestamp("⚠️ IP地址配置异常，重新配置...");
    WiFi.softAPConfig(apIP, gateway, subnet);
    delay(AP_CONFIG_DELAY);
    actualIP = WiFi.softAPIP();
  }
  
  logWithTimestamp(String("📍 AP IP: ") + actualIP.toString());
  apMode = true;
  return true;
}

bool WiFiManager::startDNSServer() {
  if (dnsServer) {
    delete dnsServer;
  }
  dnsServer = new DNSServer();
  
  IPAddress currentIP = WiFi.softAPIP();
  logWithTimestamp(String("🌐 DNS服务器使用IP: ") + currentIP.toString());
  
  bool dnsStarted = dnsServer->start(53, "*", currentIP);
  logWithTimestamp(String("🌐 DNS服务器启动: ") + (dnsStarted ? "成功" : "失败"));
  
  if (!dnsStarted) {
    logWithTimestamp("⚠️ DNS启动失败，重试...");
    delay(DNS_START_RETRY_DELAY);
    dnsStarted = dnsServer->start(53, "*", currentIP);
    logWithTimestamp(String("🌐 DNS重试结果: ") + (dnsStarted ? "成功" : "失败"));
  }
  
  return dnsStarted;
}

void WiFiManager::setupCaptivePortalRoutes() {
  // Captive Portal路由 - 针对手机优化
  server->on("/", [this](){ 
    stats.portalRequests++;
    logWithTimestamp("📱 收到根路径请求"); 
    this->handleCaptivePortal(); 
  });
  server->on("/config", [this](){ 
    stats.portalRequests++;
    logWithTimestamp("📱 收到config路径请求"); 
    this->handleWiFiConfig(); 
  });
  server->on("/save", HTTP_POST, [this](){ this->handleWiFiSave(); });
  server->on("/reset", [this](){ this->handleWiFiReset(); });
  server->on("/ping", [this](){ 
    logWithTimestamp("🏓 收到ping请求"); 
    server->send(200, "text/plain", "pong"); 
  });
  server->on("/test", [this](){ 
    logWithTimestamp("🧪 收到测试请求"); 
    this->handleNetworkTest(); 
  });
  
  // 系统调试端点
  server->on("/simple", [this](){ 
    logWithTimestamp("🔍 收到简单测试请求"); 
    server->send(200, "text/plain", "ESP32 HTTP服务器工作正常!"); 
  });
  server->on("/debug", [this](){ 
    logWithTimestamp("🐛 收到调试信息请求"); 
    server->send(200, "text/plain", getPerformanceJson()); 
  });
  
  // 手机Captive Portal检测路径 - 直接定义每个路径
  server->on("/generate_204", [this](){
    stats.portalRequests++;
    logWithTimestamp("🤖 Android检测: /generate_204");
    this->handleCaptivePortal();
  });
  server->on("/gen_204", [this](){
    stats.portalRequests++;
    logWithTimestamp("🤖 Android检测: /gen_204");
    this->handleCaptivePortal();
  });
  server->on("/redirect", [this](){
    stats.portalRequests++;
    logWithTimestamp("🤖 Android检测: /redirect");
    this->handleCaptivePortal();
  });
  server->on("/captive-portal", [this](){
    stats.portalRequests++;
    logWithTimestamp("🤖 Android检测: /captive-portal");
    this->handleCaptivePortal();
  });
  server->on("/hotspot-detect.html", [this](){
    stats.portalRequests++;
    logWithTimestamp("🍎 iOS检测: /hotspot-detect.html");
    this->handleCaptivePortal();
  });
  server->on("/library/test/success.html", [this](){
    stats.portalRequests++;
    logWithTimestamp("🍎 iOS检测: /library/test/success.html");
    this->handleCaptivePortal();
  });
  server->on("/success.txt", [this](){
    stats.portalRequests++;
    logWithTimestamp("🍎 iOS检测: /success.txt");
    this->handleCaptivePortal();
  });
  server->on("/mobile/status.php", [this](){
    stats.portalRequests++;
    logWithTimestamp("🍎 iOS检测: /mobile/status.php");
    this->handleCaptivePortal();
  });
  server->on("/connecttest.txt", [this](){
    stats.portalRequests++;
    logWithTimestamp("🪟 Windows检测: /connecttest.txt");
    this->handleCaptivePortal();
  });
  server->on("/ncsi.txt", [this](){
    stats.portalRequests++;
    logWithTimestamp("🪟 Windows检测: /ncsi.txt");
    this->handleCaptivePortal();
  });
  server->on("/fwlink/", [this](){
    stats.portalRequests++;
    logWithTimestamp("🪟 Windows检测: /fwlink/");
    this->handleCaptivePortal();
  });
  server->on("/redirect/", [this](){
    stats.portalRequests++;
    logWithTimestamp("🪟 Windows检测: /redirect/");
    this->handleCaptivePortal();
  });
  server->on("/msftconnecttest/connecttest.txt", [this](){
    stats.portalRequests++;
    logWithTimestamp("🪟 Windows检测: /msftconnecttest/connecttest.txt");
    this->handleCaptivePortal();
  });
  server->on("/kindle-wifi/wifiredirect.html", [this](){
    stats.portalRequests++;
    logWithTimestamp("📱 Kindle检测");
    this->handleCaptivePortal();
  });
  
  // 拒绝的路径
  server->on("/wpad.dat", [this](){ server->send(404, "text/plain", ""); });
  server->on("/favicon.ico", [this](){ server->send(404, "text/plain", ""); });
  
  server->onNotFound([this](){ 
    stats.portalRequests++;
    logWithTimestamp(String("📱 未知路径: ") + server->uri() + " 客户端: " + server->client().remoteIP().toString());
    this->handleCaptivePortal(); 
  });
}

bool WiFiManager::setupWebRoutes() {
  if (server) {
    server->stop();
    delete server;
  }
  
  server = new WebServer(DEFAULT_AP_PORT);
  setupCaptivePortalRoutes();
  
  server->begin(DEFAULT_AP_PORT);
  serverRunning = true;
  
  logWithTimestamp("🌐 Web服务器在端口80启动");
  return true;
}

void WiFiManager::updateConnectionStats(bool connected) {
  stats.totalConnections++;
  if (connected) {
    stats.successfulConnections++;
    stats.currentConnectionStart = millis();
  } else {
    stats.failedConnections++;
  }
}

void WiFiManager::updateSignalStats() {
  if (isConnected()) {
    int rssi = WiFi.RSSI();
    if (rssi > stats.bestSignalStrength) {
      stats.bestSignalStrength = rssi;
    }
    if (rssi < stats.worstSignalStrength) {
      stats.worstSignalStrength = rssi;
    }
  }
}

void WiFiManager::logPerformanceMetrics() {
  logWithTimestamp("=== WiFi 性能统计 ===");
  logWithTimestamp(String("总连接次数: ") + stats.totalConnections);
  logWithTimestamp(String("成功连接: ") + stats.successfulConnections);
  logWithTimestamp(String("失败连接: ") + stats.failedConnections);
  logWithTimestamp(String("Web请求: ") + stats.webRequests);
  logWithTimestamp(String("Portal请求: ") + stats.portalRequests);
  logWithTimestamp(String("最佳信号: ") + stats.bestSignalStrength + " dBm");
  logWithTimestamp(String("内存剩余: ") + ESP.getFreeHeap() + " bytes");
}

void WiFiManager::resetStats() {
  memset(&stats, 0, sizeof(stats));
  stats.bestSignalStrength = -100;
  logWithTimestamp("📊 性能统计已重置");
}

void WiFiManager::printPerformanceReport() {
  Serial.println("=================== WiFi性能报告 ===================");
  Serial.printf("📊 连接统计:\n");
  Serial.printf("   总连接次数: %lu\n", stats.totalConnections);
  Serial.printf("   成功连接: %lu (%.1f%%)\n", stats.successfulConnections, 
    stats.totalConnections > 0 ? (float)stats.successfulConnections / stats.totalConnections * 100 : 0);
  Serial.printf("   失败连接: %lu (%.1f%%)\n", stats.failedConnections,
    stats.totalConnections > 0 ? (float)stats.failedConnections / stats.totalConnections * 100 : 0);
  Serial.printf("   断开次数: %lu\n", stats.totalDisconnections);
  
  Serial.printf("📶 信号质量:\n");
  Serial.printf("   最佳信号: %d dBm\n", stats.bestSignalStrength);
  Serial.printf("   最差信号: %d dBm\n", stats.worstSignalStrength);
  Serial.printf("   当前信号: %d dBm\n", isConnected() ? WiFi.RSSI() : -100);
  
  Serial.printf("🌐 服务器统计:\n");
  Serial.printf("   Web请求: %lu\n", stats.webRequests);
  Serial.printf("   Portal请求: %lu\n", stats.portalRequests);
  Serial.printf("   数据传输: %lu bytes\n", stats.totalDataTransferred);
  
  Serial.printf("💾 系统信息:\n");
  Serial.printf("   剩余内存: %d bytes\n", ESP.getFreeHeap());
  Serial.printf("   运行时间: %lu ms\n", millis());
  
  if (stats.currentConnectionStart > 0 && isConnected()) {
    unsigned long connectionTime = millis() - stats.currentConnectionStart;
    Serial.printf("   当前连接时长: %lu ms\n", connectionTime);
    if (connectionTime > stats.longestConnectionTime) {
      stats.longestConnectionTime = connectionTime;
    }
  }
  Serial.printf("   最长连接时长: %lu ms\n", stats.longestConnectionTime);
  Serial.println("===================================================");
}

String WiFiManager::getPerformanceJson() {
  StaticJsonDocument<512> doc;
  
  doc["ap_mode"] = apMode;
  doc["wifi_connected"] = isConnected();
  doc["server_running"] = serverRunning;
  doc["dns_running"] = (dnsServer != nullptr);
  
  if (isConnected()) {
    doc["wifi_ssid"] = WiFi.SSID();
    doc["wifi_ip"] = WiFi.localIP().toString();
    doc["signal_strength"] = WiFi.RSSI();
  }
  
  if (apMode) {
    doc["ap_clients"] = WiFi.softAPgetStationNum();
    doc["ap_ip"] = WiFi.softAPIP().toString();
  }
  
  JsonObject statsObj = doc.createNestedObject("stats");
  statsObj["total_connections"] = stats.totalConnections;
  statsObj["successful_connections"] = stats.successfulConnections;
  statsObj["failed_connections"] = stats.failedConnections;
  statsObj["web_requests"] = stats.webRequests;
  statsObj["portal_requests"] = stats.portalRequests;
  statsObj["best_signal"] = stats.bestSignalStrength;
  statsObj["worst_signal"] = stats.worstSignalStrength;
  statsObj["data_transferred"] = stats.totalDataTransferred;
  
  doc["free_memory"] = ESP.getFreeHeap();
  doc["uptime"] = millis();
  
  String result;
  serializeJson(doc, result);
  return result;
}
